<template>
  <div class="play_container" :id="id">
    <video
      :ref="`videoPlayer_${id}`"
      class="video-js vjs-default-skin vjs-big-play-centered video_container"
      :style="{
        width
      }"
    ></video>
  </div>
</template>
<script>
import videojs from "video.js";
import "videojs-markers";
import "videojs-markers/dist/videojs.markers.css";

const enumPointType = {
  QUESTION: "提问时间点",
  INTERACTION: "互动时间点",
  PRACTICE: "练习时间点",
  CONCENTRATE: "专注时间点",
  LAZY: "散漫时间点"
};
const videoList = [
  {
    video_name: "测试1",
    play_url: "http://1305104382.vod2.myqcloud.com/ddc31425vodtranscq1305104382/2da1f0da1397757887181729164/v.f100240.m3u8"
  },
  {
    video_name: "测试2",
    play_url: "http://1305104382.vod2.myqcloud.com/ddc31425vodtranscq1305104382/2da1f0da1397757887181729164/v.f100240.m3u8"
  }
];
export default {
  props: {
    id: {
      type: String,
      default: ""
    },
    width: {
      type: String,
      default: "100%"
    },

    height: {
      type: String,
      default: "515px"
    },
    marker: {
      type: Object,
      default: () => {}
    },
    videoList: {
      type: Array,
      default: () => []
    },
    url: {
      type: String,
      default: ""
    }
  },
  data() {
    return {
      recordSegmentation: {}, // 记录打点被视频分段时间 ：打点时间段跨视频
      playedTotalTime: 0, // 已经播放的时长
      playCom: null,
      fullCom: null,
      listDom: null,
      player: null,
      totalTime: 0, // 总时长
      currentTime: 0, // 当前时间
      currentPoint: "", // 当前的点
      isSame: false, // 是否为相同的点
      isPlay: false, // 当前是否在播放
      isFull: false, // 是否全屏
      markerDataInfo: {},
      markerBtn: [], // 提问按钮
      isShowPlay: false,
      playing: 0 // 默认高亮播放第一个
    };
  },

  watch: {
    url(newValue) {
      if (this.player) {
        this.player.src({ type: "application/x-mpegURL", src: newValue });
      } else {
        this.init();
        this.videoMarkerData();
        this.initMarkerBtn();
      }
    }
  },

  computed: {
    formatTime() {
      return (time) => {
        // 将总时间转换为整数秒数
        const totalSeconds = Math.floor(time);

        // 计算小时、分钟和秒数
        const hours = Math.floor(totalSeconds / 3600);
        const minutes = Math.floor((totalSeconds % 3600) / 60);
        const seconds = totalSeconds % 60;

        // 格式化为 "00:00:00" 形式
        const formattedTime = ("0" + hours).slice(-2) + ":" + ("0" + minutes).slice(-2) + ":" + ("0" + seconds).slice(-2);

        return formattedTime;
      };
    }
  },
  methods: {
    // 初始化播放器
    init() {
      const host_addr = sessionStorage.getItem("host_addr");
      const video_url = host_addr + "/video/20240308/video_d239c75c0d008fdd3a95a7aa96cedc8a.mp4";
      const options = {
        autoplay: true, // 自动播放
        language: "zh-CN",
        controls: true, // 控制条
        preload: "auto", // 自动加载
        errorDisplay: true, // 错误展示
        userActions: {
          hotkeys: true // 是否支持热键
        },
        notSupportedMessage: "此视频暂无法播放，请稍后再试",
        sources: [
          // {
          //   src: "http://1305104382.vod2.myqcloud.com/ddc31425vodtranscq1305104382/2da1f0da1397757887181729164/v.f100240.m3u8",
          //   type: "application/x-mpegURL"
          // }
        ],
        controlBar: {
          /* 设置控制条里面组件的相关属性及显示与否  */
          remainingTimeDisplay: false,

          children: [
            { name: "progressControl" },
            {
              name: "volumePanel", // 音量控制
              inline: false // 不使用水平方式
            }
          ]
        }
      };

      // 判断视频类型 m3u8或者是MP4
      this.handleDtermine(options);

      this.player = videojs(this.$refs[`videoPlayer_${this.$props.id}`], options, () => {
        videojs.log(`Your player is ready!`);
        // 获取视频总时间
        this.getVideoDuration();
        // 打点
        this.markers();
      });

      this.player.on("timeupdate", (e) => {
        // 计算当前时间并显示
        const currenTime = e.target.player.currentTime ? Math.floor(e.target.player.currentTime()) : "";
        this.currentTime = this.formatTime(currenTime);
        const pDom = document.querySelector(`.vjs-progress-text_${this.$props.id}`);
        const cDom = pDom.querySelector(".vjs-control-text");

        cDom.innerText = `${this.currentTime} / ${this.totalTime}`;
      });

      this.player.on("play", () => {
        this.isPlay = true;
        this.formatText();
      });

      this.player.on("pause", () => {
        this.isPlay = false;
        this.formatText();
      });

      this.player.on("ended", () => {
        this.isPlay = false;
        this.handlePlayNext();

        this.formatText();
      });

      this.player.on("fullscreenchange", (e, a) => {
        console.info(e, a);
        this.isFull = !this.isFull;
        this.formatFull();
      });
    },

    // 播放下一个
    handlePlayNext() {
      const { videoList } = this.$props;

      const nextVideo = videoList.find((item, index) => {
        if (index === this.playing + 1) return item;
      });

      // 存在视频
      if (nextVideo) {
        this.playing++;
        this.player.src({ type: "application/x-mpegURL", src: nextVideo.play_url });

        const videoDomArray = Array.from(this.listDom.querySelectorAll(".video_item"));
        let targetItem;
        for (let i = 0; i < videoDomArray.length; i++) {
          if (videoDomArray[i].className.includes("active_item") && i < videoDomArray.length - 1) {
            targetItem = videoDomArray[i + 1];
          }
        }

        targetItem && this.handleHighlight(targetItem);
      }
    },

    // 高亮视频列表样式
    handleHighlight(highlightDom) {
      const videoDomArray = this.listDom.querySelectorAll(".video_item");
      Array.from(videoDomArray).forEach((item) => item.classList.remove("active_item"));
      highlightDom.classList.add("active_item");
    },

    // 点击视频列表并加上选中样式
    handleClickVideo(event, selectVidoe, index) {
      this.playing = index;
      this.handleHighlight(event.target);
      this.getVideoDuration();
      this.player.src({ type: "application/x-mpegURL", src: selectVidoe.play_url });

      this.videoMarkerData();
    },

    // 创建视频文档碎片
    createVideoItemDom() {
      const { videoList } = this.$props;

      const domFramgment = document.createDocumentFragment();
      videoList.forEach((item, index) => {
        const divItem = document.createElement("div");
        divItem.classList.add("video_item");
        if (this.playing === index) {
          divItem.classList.add("active_item");
        }
        divItem.setAttribute("title", item.video_name);
        divItem.innerText = `${index + 1}、${item.video_name}`;
        divItem.addEventListener("click", (event) => {
          this.handleClickVideo(event, item, index);
        });
        domFramgment.appendChild(divItem);
      });

      this.listDom.appendChild(domFramgment);
    },

    // 创建视频列表
    handleAddPlayListDom() {
      const domInstance = document.getElementById(this.$props.id);
      const dom = domInstance.querySelector(".video-js");
      this.listDom = document.createElement("div");
      this.listDom.classList.add("video_list");
      this.listDom.style.display = "none";
      dom.appendChild(this.listDom);

      this.createVideoItemDom();
    },

    // 判断视频类型 mp4 或是m3u8
    handleDtermine(options) {
      const url = this.$props.url;
      const extension = url.substring(url.lastIndexOf(".") + 1);
      if (extension === "mp4") {
        options.sources.push({
          src: url,
          type: "video/mp4"
        });
      } else {
        options.sources.push({
          src: url,
          type: "application/x-mpegURL"
        });
      }
    },

    // 显示打点
    markers() {
      this.player.markers({
        markerStyle: {
          // 标记点样式
          width: "0.2em",
          height: "0.3em",
          "background-color": "#15C136",
          position: "absolute"
        },

        //鼠标移入标记点的提示
        markerTip: {
          display: true, // 是否显示
          /*
            用于动态构建标记提示文本的回调函数。
            只需返回一个字符串，参数标记是传递给插件的标记对象
          */
          text: function (marker) {
            return marker.text;
          }
        },

        // 点
        markers: []
      });
    },

    // 处理视频点的回调
    handleControl(type) {
      let markerOption = [];

      switch (type) {
        case enumPointType.QUESTION:
          markerOption = this.markerDataInfo.question;
          break;
        case enumPointType.INTERACTION:
          markerOption = this.markerDataInfo.interaction;
          break;
        case enumPointType.PRACTICE:
          markerOption = this.markerDataInfo.practice;
          break;
        case enumPointType.CONCENTRATE:
          markerOption = this.markerDataInfo.concentrate;
          break;
        case enumPointType.LAZY:
          markerOption = this.markerDataInfo.lazy;
          break;
      }
      this.player.markers.reset(markerOption);
      const allBtn = document.querySelectorAll(`.vjs-custom-btn-${this.$props.id}`);
      Array.from(allBtn).forEach((item) => item.classList.remove("active_btn"));
      const cliclNode = Array.from(allBtn).find((item) => item.innerText === type);
      cliclNode.classList.add("active_btn");

      if (this.currentPoint === type && !this.isSame) {
        this.player.markers.reset([]);
        this.isSame = true;
        cliclNode.classList.remove("active_btn");
      } else {
        this.isSame = false;
      }
      this.currentPoint = type;
    },

    // 初始化自定义控件
    initControl() {
      this.initPlayBtnControl();
      this.initPlayListControl();
      this.initFullScreenControl();
      this.handleAddPlayListDom();
      // 自定义进度时间控件
      this.player.getChild("ControlBar").addChild("button", {
        controlText: `${this.currentTime} / ${this.totalTime}`,
        className: `vjs-visible-text vjs-progress-text_${this.$props.id}`
      });

      this.markerBtn.forEach((item) => {
        this.player.getChild("ControlBar").addChild("button", {
          controlText: item,
          className: `vjs-visible-text vjs-conmon-btn vjs-custom-btn-${this.$props.id}`,
          clickHandler: () => {
            this.handleControl(item);
          }
        });
      });
    },

    // 暂停播放控件
    initPlayBtnControl() {
      const _that = this;
      // 自定义播放按钮
      const baseComponent = videojs.getComponent("Component");

      const myComponent = videojs.extend(baseComponent, {
        constructor: function (player, options) {
          baseComponent.apply(this, arguments);
          this.on("click", this.clickBtn);
        },
        createEl: function () {
          const pauseUrl = require("../../../assets/images/ai/pause.png");
          const playUrl = require("../../../assets/images/ai/play.png");

          _that.playCom = videojs.dom.createEl("div", {
            className: "vjs-my-components",
            innerHTML: `<img style="cursor: pointer;" src="${_that.isPlay ? pauseUrl : playUrl}"  alt="${_that.isPlay ? "暂停" : "播放"}" />`
          });

          return _that.playCom;
        },
        clickBtn: this.handleClickBtn
      });

      videojs.registerComponent("myComponent", myComponent);

      // 找到 controlBar 节点，添加控件
      this.player.getChild("controlBar").addChild("myComponent");
    },

    // 全屏控件
    initFullScreenControl() {
      const _that = this;

      // 自定义播放按钮
      const baseComponent = videojs.getComponent("Component");

      const fullComponent = videojs.extend(baseComponent, {
        constructor: function (player, options) {
          baseComponent.apply(this, arguments);
          this.on("click", this.clickBtn);
        },
        createEl: function () {
          const url = require("../../../assets/images/ai/full.png");
          _that.fullCom = videojs.dom.createEl("div", {
            className: "vjs-full-components",
            innerHTML: `<img  style="cursor: pointer;" title="${_that.isFull ? "还原" : "全屏"}" src="${url}" alt="${_that.isFull ? "还原" : "全屏"}" />`
          });

          return _that.fullCom;
        },
        clickBtn: this.handleClickFull
      });
      videojs.registerComponent("fullComponent", fullComponent);

      // 找到 controlBar 节点，添加控件
      this.player.getChild("controlBar").addChild("fullComponent");
    },

    // 自定义播放列表控件
    initPlayListControl() {
      // 自定义播放按钮
      const baseComponent = videojs.getComponent("Component");

      const playComponent = videojs.extend(baseComponent, {
        constructor: function (player, options) {
          baseComponent.apply(this, arguments);
          this.on("click", this.clickBtn);
        },
        createEl: function () {
          const url = require("../../../assets/images/ai/video_list.png");
          const playList = videojs.dom.createEl("div", {
            className: "vjs-play-components",
            innerHTML: `<img  style="cursor: pointer;" title="视频列表" src="${url}"  />`
          });

          return playList;
        },
        clickBtn: this.handleClickPlay
      });
      videojs.registerComponent("playComponent", playComponent);

      // 找到 controlBar 节点，添加控件
      this.player.getChild("controlBar").addChild("playComponent");
    },

    // 播放列表
    handleClickPlay() {
      this.isShowPlay = !this.isShowPlay;
      this.listDom.style.display = this.isShowPlay ? "inline-block" : "none";
    },

    // 点击播放暂停按钮触发事件
    handleClickBtn() {
      this.isPlay = !this.isPlay;
      if (this.isPlay) {
        this.player.play();
      } else {
        this.player.pause();
      }
      this.formatText();
    },

    // 全屏
    handleClickFull() {
      this.isFull = !this.isFull;
      console.info(this.isFull);
      if (this.isFull) {
        this.player.requestFullscreen();
      } else {
        this.player.exitFullscreen();
      }

      this.formatFull();
    },

    // 更换暂停播放icon
    formatText() {
      const pauseUrl = require("../../../assets/images/ai/pause.png");
      const playUrl = require("../../../assets/images/ai/play.png");
      this.playCom.innerHTML = `<img style="cursor: pointer;" title="${this.isPlay ? "暂停" : "播放"}" src="${this.isPlay ? pauseUrl : playUrl}"  alt="${this.isPlay ? "暂停" : "播放"}" />`;
    },

    // 更换全屏icon
    formatFull() {
      const url = require("../../../assets/images/ai/full.png");
      this.fullCom.innerHTML = `<img style="cursor: pointer;" title="${this.isFull ? "还原" : "全屏"}" src="${url}" alt="${this.isFull ? "还原" : "全屏"}" />`;
    },

    // 获取总时长
    getVideoDuration() {
      this.player.on("loadedmetadata", () => {
        const totalTime = this.player.duration();
        this.totalTime = this.formatTime(totalTime);

        console.info("totalTime", this.$props.id, totalTime);
      });
    },

    // 转换打点时间 转为时间段 [{time:0,text:'提问',duration:10}]
    videoMarkerData() {
      const { marker } = this.$props;

      const btn = []; // 显示的按钮控件
      const resultObj = {};
      for (const key in marker) {
        const result = [];
        let start = null;
        for (let i = 0; i < marker[key].length; i++) {
          if (marker[key][i]) {
            start = marker[key][i].Start;
            result.push({
              time: start,
              text: enumPointType[key.toLocaleUpperCase()],
              duration: marker[key][i].End - marker[key][i].Start
            });
            btn.push(enumPointType[key.toLocaleUpperCase()]);
            start = null;
          }
        }

        if (result.length) resultObj[key] = result;
      }

      this.markerDataInfo = resultObj;
      this.markerBtn = Array.from(new Set(btn));

      this.handleVideoPoint(resultObj);
    },

    //处理视频每一段的打点
    handleVideoPoint(resultObj) {
      const { videoList } = this.$props;
      const { playing, recordSegmentation } = this;
      // 当前播放的视频
      const playingVideo = videoList[playing];

      // 已经播放完的视频时间长度 当播放下一段视频时需要减去已经播放的长度
      for (let i = 0; i < playing; i++) {
        this.playedTotalTime += videoList[i].video_length;
      }

      const currentPlayMark = {};
      for (const key in resultObj) {
        resultObj[key].forEach((item) => {
          if (item.time - this.playedTotalTime >= 0 && playingVideo.video_length > item.time - this.playedTotalTime) {
            item.time -= this.playedTotalTime;
            if (playingVideo.video_length < item.time + item.duration) {
              recordSegmentation[key] = { duration: item.duration + item.time - playingVideo.video_length };
              item.duration = playingVideo.video_length - item.time;
            }
            if (!currentPlayMark[key]) {
              currentPlayMark[key] = [];
              currentPlayMark[key].push(item);
            } else {
              currentPlayMark[key].push(item);
            }
          }
        });
      }

      // 当前播放视频的index不为0 则当前播放的视频为非第一段视频 如果存在打点跨段 则需要补充上来
      if (playing) {
        for (const key in recordSegmentation) {
          if (currentPlayMark[key]) {
            currentPlayMark[key].unshift({
              duration: recordSegmentation[key].duration,
              time: 0,
              text: enumPointType[key.toLocaleUpperCase()]
            });
          }
        }
      }

      this.markerDataInfo = currentPlayMark;
    },

    initMarkerBtn() {
      // 自定义控件
      this.initControl();
    }
  },
  mounted() {
    if (this.$props.url) {
      this.init();
      this.videoMarkerData();
      this.initMarkerBtn();
    }
  },
  beforeDestroy() {
    if (this.player) {
      this.player.dispose();
    }
  }
};
</script>
<style lang="scss">
.play_container {
  position: relative;

  display: flex;
  justify-content: center;
  padding-bottom: 20px;

  .video_list {
    position: absolute;
    top: 0;
    right: 0;
    width: 200px;
    height: calc(100% - 60px);
    background-color: rgba(255, 255, 255, 0.2);
    justify-content: center;
    padding-top: 10px;
    padding-left: 5px;
    overflow-y: auto;

    .video_item {
      font-size: 12px;
      width: 190px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      cursor: pointer;
      margin-bottom: 8px;
      padding-bottom: 11px;
      border-bottom: 1px solid rgba(255, 255, 255, 0.15);
    }

    .active_item {
      color: #66ffff;
    }
  }
}

.video_container {
  width: 90%;
  height: 484px;
}

// 进度条
.vjs-progress-control {
  position: absolute !important;
  width: 100% !important;
  bottom: 55px;
  height: 1rem !important;

  .vjs-progress-holder {
    margin: 0 !important;
  }

  .vjs-slider-bar {
    background-color: #5fedf0 !important;
  }
}

.vjs-control-bar {
  height: 5rem !important;
  background-color: #1d345c !important;
  align-items: center;
}

// 自定义控件样式
.vjs-volume-panel {
  position: absolute !important;
  right: 45px;
  top: 15px;
}

.vjs-visible-text {
  margin: 0 10px !important;
}

.vjs-progress-text {
  margin-right: 120px !important;
}

.vjs-conmon-btn {
  box-sizing: border-box !important;
  border-radius: 6px !important;
  height: 30px !important;
  background: rgba(49, 138, 194, 0.3) !important;
  letter-spacing: 1px;
}

.vjs-my-components {
  margin-left: 20px;
}
.vjs-full-components {
  position: absolute;
  right: 55px;
}

.vjs-play-components {
  position: absolute;
  right: 15px;
}

.vjs-mute-control {
  position: absolute !important;
  right: 35px;
}

.vjs-playDom-components {
  position: absolute;
  top: 0;
  right: 0;
  width: 200px;
  height: calc(100% - 80px);
  background-color: rgba(255, 255, 255, 0.2);
}

.vjs-play-progress {
  &::before {
    font-size: 0 !important;
  }
}

.video-js .vjs-control-bar {
  visibility: visible !important;
  opacity: 1 !important;
  transition: none !important;
}

video:focus {
  outline: -webkit-focus-ring-color auto 0px;
}

.active_btn {
  background-color: #318ac2 !important;
}

.vjs-marker {
  &:hover {
    transform: scale(1) !important;
  }
}
</style>
